package com.example.selfservicestation.util

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

class NetManager private constructor(ctx: Context) {

    @Volatile
    private var available = false

    val liveData = MutableLiveData<Boolean>()

    private val latch = CountDownLatch(1)

    private val callback = object : ConnectivityManager.NetworkCallback() {

        override fun onAvailable(network: Network) {
            liveData.postValue(true)
            available = true
            latch.countDown()
        }

        override fun onUnavailable() {
            liveData.postValue(false)
            available = false
            latch.countDown()
        }

        override fun onLost(network: Network) {
            liveData.postValue(false)
            available = false
            latch.countDown()
        }

    }

    init {
        (ctx.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?)
            ?.run {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    registerDefaultNetworkCallback(callback)
                } else {
                    registerNetworkCallback(NetworkRequest.Builder().build(), callback)
                }
            }
    }

    /**
     * 当前是否有网络，不能在主线程使用
     */
    @WorkerThread
    fun isAvailable() : Boolean {
        liveData.value?.let {
            return it
        }
        latch.await(100, TimeUnit.MILLISECONDS)
        return available
    }

    companion object {

        @Volatile
        private var instance: NetManager? = null

        fun getInstance(ctx: Context): NetManager {
            return instance ?: synchronized(this) {
                instance ?: NetManager(ctx)
                    .also {
                        instance = it
                    }
            }
        }

    }

}

abstract class OnceNetObserver : Observer<Boolean> {

    private var observed = false

    final override fun onChanged(value: Boolean) {
        synchronized(this) {
            if (value && !observed) {
                onNetAvailable()
                observed = true
            }
        }
    }

    abstract fun onNetAvailable()

}